<?php

/**
 * 角色模型
 *
 * @author JiangJian <silverd@sohu.com>
 * @copyright 2011-2012 xiangle.com
 * $Id: Privilege.php 162 2012-11-09 04:04:30Z Jun.Lu.726@gmail.com $
 * @version    2012-02-16  ::  JiangJian  ::  Create File
 */
class Model_System_Privilege extends Model_AbstractDao
{

    protected $_dbName     = 'BingoMobi';
    protected $_tableName  = 'bg_sys_privilege';
    protected $_primaryKey = 'priv_id';
    protected $_nameField  = 'priv_name';

    /**
     * 根据MCA获取对应权限颗粒id
     *
     * @param string $module
     * @param string $controller
     * @param string $action
     * @return int
     */
    public function getPrivByMCA($controller, $action)
    {
        return $this->_db()->fetchOne("SELECT priv_id FROM `bg_sys_privilege` WHERE `controller` = '{$controller}' AND action = '{$action}'");
    }

    /**
     * 获取关联数组列表（三维数组）
     * 返回形式如：Array[module][controller][action] = privInfo
     *
     * @param mixed $whereArr
     * @param string $orderBy
     * @return array
     */
    public function getAssocList($whereArr = array(), $orderBy = 'controller ASC, action ASC')
    {
        ;
        $privList = $this->findByPage($whereArr, 0, 0, $orderBy);
        if (!$privList) {
            return array();
        }

        $return = array();
        foreach ($privList as $value) {
            $return[$value['controller']][$value['action']] = array(
                'priv_id'   => $value['priv_id'],
                'priv_name' => $value['priv_name'],
            );
        }
        return $return;
    }

    /**
     * 添加一条
     *
     * @param array $data
     * @return bool
     */
    public function add($data)
    {
        $data = Helper_String::deepFilterDatas($data, array('trim', 'strip_tags'));

        // 检测合法性
        if (!$data['priv_name'] || !$data['controller'] || !$data['action']) { //  !$data['module'] ||
            return '权限名、控制器名、方法名必填'; // 模块名、
        }

        $setArr = array(
            'priv_name'  => $data['priv_name'],
            //  'module'     => $data['module'],
            'controller' => $data['controller'],
            'action'     => $data['action'],
        );

        if (!$this->_db()->replace('bg_sys_privilege', $setArr)) {
            return '添加权限入库失败';
        }

        return true;
    }

    /**
     * 更新一条（目前只能修改权限名）
     *
     * @param array $data
     * @return bool
     */
    public function update1($privId, $data)
    {
        $privId = intval($privId);
        if ($privId < 1) {
            return '权限id非法';
        }

        $data = Helper_String::deepFilterDatas($data, array('trim', 'strip_tags'));

        // 检测合法性
        if (!$data['priv_name']) {
            return '权限名必填';
        }

        $setArr = array(
            'priv_name' => $data['priv_name'],
        );

        if (!$this->_db()->update('bg_sys_privilege', $setArr, "priv_id = '{$privId}'")) {
            return '更新权限入库失败';
        }

        return true;
    }

    /**
     * 获取权限颗粒列表（从文件系统中扫描得出）
     *
     * @return array
     */
    public function getMethodListFromFileSystem()
    {
        $ignoreList = array('Abstract.php');
        // 获取控制器目录的文件目录树
        $fileTree = $this->_getFileTree(APP_PATH . 'Class' . DS . 'Controller', $ignoreList);

        if (!$fileTree) {
            return array();
        }


        // 将目录树转换为数组
        // 格式如：$methodList[Module][Controller] = array(MethodInfo1, MethodInfo2 ...)
        $methodList = array();

        foreach ($fileTree as $module => $controllerFiles) {
            // 对控制器进行文件归类
            if (is_array($controllerFiles) && !empty($controllerFiles)) {
                foreach ($controllerFiles as $controllerFileName) {

                    // 转换控制器类名
                    $controller          = basename($controllerFileName, '.php');
                    $controllerClassName = 'Controller_' . $module . '_' . $controller;

                    $methodList[$module][$module . '_' . $controller] = $this->getMethodInfo($controller, $controllerClassName);
                }
            }
            // 最外层控制器
            if (is_string($controllerFiles) && !empty($controllerFiles)) {
                // 转换控制器类名
                $controller = basename($controllerFiles, '.php');

                $controllerClassName = 'Controller_' . $controller;

                $methodList[][$controller] = $this->getMethodInfo($controller, $controllerClassName);
            }
        }
        return $methodList;
    }

    /**
     * 获取控制器信息
     *
     * @param type $controller
     * @param type $controllerClassName
     * @return type
     */
    public function getMethodInfo($controller, $controllerClassName)
    {
        $authObj = Model('System_Auth');

        // 获取每个控制器的所有方法（包括方法名、方法注释标题）
        $methods = $this->_getClassMethods($controllerClassName);

        // 过滤掉不检查权限的方法（即不需要分配权限）
        if ($methods) {
            foreach ($methods as $key => $method) {
                if (!$authObj->needAuthCheck($controller, $method['action'])) {
                    unset($methods[$key]);
                }
            }
        }
        return $methods;
    }

    /**
     * 获取指定目录的文件目录树
     *
     * @param string $dirPath 目录路径
     * @param array $ignoreList 需要忽略的路径
     * @return array
     */
    private function _getFileTree($dirPath, $ignoreList = array())
    {
        $return = array();

        // 需要忽略的路径
        $ignoreList = array_merge(array('.', '..'), $ignoreList);

        foreach (new DirectoryIterator($dirPath) as $file) {

            $fileName = $file->getFilename();
            // 排除无需扫描的
            if (in_array($fileName, $ignoreList) || strpos($fileName, '.svn') !== false) {
                continue;
            }

            // 是目录则递归处理
            if ($file->isDir()) {
                $return[$fileName] = $this->_getFileTree($dirPath . DS . $fileName);
            } else {
                if (strpos($fileName, '.php') !== false) {
                    $return[] = $fileName;
                }
            }
        }

        return $return;
    }

    /**
     * 获取指定类下的所有方法（包括方法名、方法注释标题）
     *
     * @param string $className
     * @return array
     */
    private function _getClassMethods($className)
    {
        if (!$className) {
            return false;
        }

        $return = array();

        $refClass   = new ReflectionClass($className);
        $refMethods = $refClass->getMethods();
        if (!$refMethods) {
            return array();
        }

        foreach ($refMethods as $refMethod) {
            if (!$refMethod->isPublic()) {
                continue;
            }

            $methodName = $refMethod->getName();
            if (substr($methodName, 0, 1) == '_' || strpos($methodName, 'Action') === false) {
                continue;
            }

            $return[] = array(
                'title'  => $this->_getCommentTitle($refMethod->getDocComment()),
                'action' => str_replace('Action', '', $methodName),
            );
        }

        return $return;
    }

    /**
     * 过滤获取注释中的标题头
     *
     * @param string $docComment
     * @return string
     */
    private function _getCommentTitle($docComment)
    {
        if ($docComment) {
            if (preg_match('/^.*?\n(.*?)\n.*/', $docComment, $matches)) {
                return isset($matches[1]) ? str_replace('* ', '', trim($matches[1])) : false;
            }
        }
        return false;
    }

}